package cn.springcloud.fix.common.core.utils;

import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.lang.Nullable;

import java.util.*;
import java.util.function.Function;

@Slf4j
public class CollectionUtil extends CollectionUtils {

    /**
     * 去除空集合
     */
    public static <T> Collection<T> removeNull(Collection<? extends T> oldCollection) {
        oldCollection.removeAll(Collections.singleton(null));
        return (Collection<T>) oldCollection;
    }

    /**
     * 传入多个非空值获取一个list
     */
    public static <T> List<T> transList(T... ts) {
        List<T> ls = new ArrayList<>();
        for (T t : ts) {
            if (t != null) {
                ls.add(t);
            }
        }
        return ls;
    }

    /**
     * Check whether the given Array contains the given element.
     *
     * @param array   the Array to check
     * @param element the element to look for
     * @param <T>     The generic tag
     * @return {@code true} if found, {@code false} else
     */
    public static <T> boolean contains(@Nullable T[] array, final T element) {
        return array != null && Arrays.stream(array).anyMatch(x -> ObjectUtil.nullSafeEquals(x, element));
    }

    /**
     * 对象是否为数组对象
     *
     * @param obj 对象
     * @return 是否为数组对象，如果为{@code null} 返回false
     */
    public static boolean isArray(Object obj) {
        return null != obj && obj.getClass().isArray();
    }

    public static <F, KT> Map extractToMap(Collection<F> collection, Function<F, KT> keyFunction, String valuePropertyName) {
        Map map = new HashMap(collection.size());
        try {
            for (F obj : collection) {
                map.put(keyFunction.apply(obj), PropertyUtils.getProperty(obj, valuePropertyName));
            }
        } catch (Exception e) {
            throw ReflectionUtil.convertReflectionExceptionToUnchecked(e);
        }
        return map;
    }

    public static <F, KT, VT> Map extractToMap(final Collection<F> collection, final Function<F, KT> keyFunction, final Function<F, VT> valueFunction) {
        Map map = new HashMap(collection.size());
        for (F obj : collection) {
            map.put(keyFunction.apply(obj), valueFunction.apply(obj));
        }
        return map;
    }

    public static <F, VT> Map extractToMap(final Collection<F> collection, final String keyPropertyName, final Function<F, VT> valueFunction) {
        Map map = new HashMap(collection.size());
        try {
            for (F obj : collection) {
                map.put(PropertyUtils.getProperty(obj, keyPropertyName), valueFunction.apply(obj));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }

    public static <F, KT> Multimap extractToMultimap(final Collection<F> collection, final Function<F, KT> keyFunction, final String valuePropertyName) {
        Multimap multimap = HashMultimap.create();
        try {
            for (F obj : collection) {
                multimap.put(keyFunction.apply(obj), PropertyUtils.getProperty(obj, valuePropertyName));
            }
        } catch (Exception e) {
            throw ReflectionUtil.convertReflectionExceptionToUnchecked(e);
        }

        return multimap;
    }

    public static <F, KT, VT> Multimap extractToMultimap(final Collection<F> collection, final Function<F, KT> keyFunction, final Function<F, VT> valueFunction) {
        Multimap multimap = HashMultimap.create();
        for (F obj : collection) {
            multimap.put(keyFunction.apply(obj), valueFunction.apply(obj));
        }

        return multimap;
    }

    public static <F, VT> Multimap extractToMultimap(final Collection<F> collection, final String keyPropertyName, final Function<F, VT> valueFunction) {
        Multimap multimap = HashMultimap.create();
        try {
            for (F obj : collection) {
                multimap.put(PropertyUtils.getProperty(obj, keyPropertyName), valueFunction.apply(obj));
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }

        return multimap;
    }

    public static Multimap extractToMultimap(final Collection collection, final String keyPropertyName, final String valuePropertyName) {
        Multimap multimap = HashMultimap.create();
        try {
            for (Object obj : collection) {
                multimap.put(PropertyUtils.getProperty(obj, keyPropertyName), PropertyUtils.getProperty(obj, valuePropertyName));
            }
        } catch (Exception e) {
            throw ReflectionUtil.convertReflectionExceptionToUnchecked(e);
        }

        return multimap;
    }

    /**
     * 提取集合中的对象的两个属性(通过Getter函数), 组合成Map.
     *
     * @param collection        来源集合.
     * @param keyPropertyName   要提取为Map中的Key值的属性名.
     * @param valuePropertyName 要提取为Map中的Value值的属性名.
     */
    public static Map extractToMap(final Collection collection, final String keyPropertyName, final String valuePropertyName) {
        Map map = new HashMap(collection.size());
        try {
            for (Object obj : collection) {
                map.put(PropertyUtils.getProperty(obj, keyPropertyName), PropertyUtils.getProperty(obj, valuePropertyName));
            }
        } catch (Exception e) {
            throw ReflectionUtil.convertReflectionExceptionToUnchecked(e);
        }

        return map;
    }

    /**
     * 提取集合中的对象的一个属性(通过Getter函数), 组合成List.
     *
     * @param collection   来源集合.
     * @param propertyName 要提取的属性名.
     */
    public static List extractToList(final Collection collection, final String propertyName) {
        List<Object> list = new ArrayList<>();
        try {
            for (Object obj : collection) {
                list.add(PropertyUtils.getProperty(obj, propertyName));
            }
        } catch (Exception e) {
            throw ReflectionUtil.convertReflectionExceptionToUnchecked(e);
        }
        return list;
    }

    /**
     * 提取集合中的对象的一个属性(通过Getter函数), 组合成由分割符分隔的字符串.
     *
     * @param collection   来源集合.
     * @param propertyName 要提取的属性名.
     * @param separator    分隔符.
     */
    public static String extractToString(final Collection collection, final String propertyName, final String separator) {
        List list = extractToList(collection, propertyName);
        return StringUtils.join(list, separator);
    }

    /**
     * 转换Collection所有元素(通过toString())为String, 中间以 separator分隔。
     */
    public static String convertToString(final Collection collection, final String separator) {
        return StringUtils.join(collection, separator);
    }

    /**
     * 转换Collection所有元素(通过toString())为String, 每个元素的前面加入prefix，后面加入postfix，如<div>mymessage</div>。
     */
    public static String convertToString(final Collection collection, final String prefix, final String postfix) {
        StringBuilder builder = new StringBuilder();
        for (Object o : collection) {
            builder.append(prefix).append(o).append(postfix);
        }
        return builder.toString();
    }

    /**
     * 判断是否为空.
     */
    public static boolean isEmpty(Collection collection) {
        return (collection == null) || collection.isEmpty();
    }

    /**
     * 判断是否为空.
     */
    public static boolean isEmpty(@Nullable Map map) {
        return !isEmpty(map);
    }

    /**
     * 判断是否为空.
     */
    public static boolean isNotEmpty(@Nullable Collection collection) {
        return !isEmpty(collection);
    }

    /**
     * 取得Collection的第一个元素，如果collection为空返回null.
     */
    public static <T> T getFirst(Collection<T> collection) {
        if (isEmpty(collection)) {
            return null;
        }
        return collection.iterator().next();
    }

    /**
     * 获取Collection的最后一个元素 ，如果collection为空返回null.
     */
    public static <T> T getLast(Collection<T> collection) {
        if (isEmpty(collection)) {
            return null;
        }

        // 当类型为List时，直接取得最后一个元素 。
        if (collection instanceof List) {
            List<T> list = (List<T>) collection;
            return list.get(list.size() - 1);
        }

        // 其他类型通过iterator滚动到最后一个元素.
        Iterator<T> iterator = collection.iterator();
        while (true) {
            T current = iterator.next();
            if (!iterator.hasNext()) {
                return current;
            }
        }
    }

    /**
     * 返回a+b的新List.
     */
    /*public static <T> List<T> union( Collection<T> a,  Collection<T> b) {
        List<T> result = new ArrayList<T>(a);
        result.addAll(b);
        return result;
    }*/

    /**
     * 返回a-b的新List.
     */
   /* public static <T> List<T> subtract( Collection<T> a,  Collection<T> b) {
        List<T> list = new ArrayList<T>(a);
        list.removeAll(b);
        return list;
    }
*/
    /**
     * 返回a与b的交集的新List.
     */
   /* public static <T> List<T> intersection(Collection<T> a, Collection<T> b) {
        List<T> list = new ArrayList<T>();

        for (T element : a) {
            if (b.contains(element)) {
                list.add(element);
            }
        }
        return list;
    }*/
}
